using System;
using System.Collections.Generic;
using System.Linq;

namespace Atomic.Structures
{
	public static class StructureDegeneracyGenerator
	{
		public static IEnumerable<StructureDegeneracy> GenerateDegeneracies(Structure lattice)
		{
			foreach (IEnumerable<Structure> structures in GenerateDegeneraciesGrouped(lattice))
			{
				yield return new StructureDegeneracy(structures.First(), structures.Count());
			}
		}

		public static IEnumerable<IEnumerable<Structure>> GenerateDegeneraciesGrouped(Structure lattice)
		{
			Dictionary<Structure, List<Structure>> degeneracies = new Dictionary<Structure, List<Structure>>();

			foreach (Structure structure in lattice.FillPlaceholdersCombinatorial())
			{
				bool found = false;

				foreach (KeyValuePair<Structure, List<Structure>> degeneracy in degeneracies)
				{
					// Same precision as SpaceGroup class default constructor.
					if (StructureEquality.SymmetryEquals(structure, degeneracy.Key, lattice, 1.0e-5))
					{
						// Already found. Add this structure to the list.
						degeneracy.Value.Add(structure);
						found = true;
						break;
					}
				}

				if (!found)
				{
					// Not found before. Add an entry with this structure as the key and a list of equivalent structure, corrently only containing this structure.
					degeneracies.Add(structure, new List<Structure>(new Structure[] { structure }));
				}
			}

			foreach (KeyValuePair<Structure, List<Structure>> degeneracy in degeneracies)
			{
				yield return degeneracy.Value;
			}
		}

		public static void GenerateDegeneracies(Structure lattice, out Structure[] structures, out double[] degeneracies)
		{
			throw new NotImplementedException();
		}

		public static IEnumerable<Structure> Generate(Structure lattice)
		{
			foreach (StructureDegeneracy degeneracy in GenerateDegeneracies(lattice))
			{
				yield return degeneracy.Structure;
			}
		}
	}
}
